package com.pi.shisan.service.audio;

import com.pi.shisan.service.util.ComponentManager;
import de.quippy.jflac.FLACDecoder;
import de.quippy.jflac.FrameDecodeException;
import de.quippy.jflac.frame.Frame;
import de.quippy.jflac.util.ByteData;

import javax.sound.sampled.AudioFormat;
import java.io.EOFException;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;

public class FlacPlayer extends AudioPlayer {

    private FileInputStream inputStream;
    private FLACDecoder flacDecoder;

    public FlacPlayer(File flacFile, AudioEffectComponentsSupplier<ComponentManager.MusicEffectBaseComponent> musicEffectComponentsSupplier) throws Exception {
        super(flacFile, musicEffectComponentsSupplier);
        init();
    }

    private void init() throws Exception {
        inputStream = new FileInputStream(audioFile);
        flacDecoder = new FLACDecoder(inputStream);
        flacDecoder.readMetadata();
        AudioFormat audioFormat = flacDecoder.getStreamInfo().getAudioFormat();
        totalMilliseconds = (int) (flacDecoder.getStreamInfo().getTotalSamples() * 1000L / (long) audioFormat.getSampleRate());
    }

    @Override
    public void doDestroy() {
        closeSource();
    }

    @Override
    protected boolean doingPlay() throws Exception {
        if (audioOutputStream == null) {
            openSound(flacDecoder.getStreamInfo().getAudioFormat());
        }
        while (playerStatus.get() == PLAYING) {
            try {
                ByteData data = decode();
                if (data != null) {
                    writeSampleData(data.getData(),0,data.getLen());
                    continue;
                }
                return true;
            } catch (EOFException e) {
                return true;
            }
        }
        return false;
    }

    @Override
    protected void reset() throws Exception {
        if (inputStream != null) {
            try {
                inputStream.close();
            } catch (Exception e) {}
        }
        inputStream = new FileInputStream(audioFile);
        flacDecoder = new FLACDecoder(inputStream);
        flacDecoder.readMetadata();
    }

    private ByteData decode() throws IOException {
        try {
            flacDecoder.findFrameSync();
            Frame currentFrame = flacDecoder.readFrame();
            if (currentFrame != null) {
                currentMilliseconds = currentFrame.getHeader().sampleNumber * 1000L / (long)flacDecoder.getSampleRate();
                return flacDecoder.decodeFrame(currentFrame, null);
            }
        } catch (FrameDecodeException ex) {
            currentMilliseconds = flacDecoder.getSamplesDecoded() * 1000L / (long)flacDecoder.getSampleRate();
        }
        return null;
    }

    private void closeSource() {
        if (inputStream != null) {
            try {
                inputStream.close();
            } catch (Exception e) {}
        }
    }
}
